package com.exception.demo.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.UnsatisfiedServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import com.exception.demo.response.ResultCode;
import com.exception.demo.response.ResultObj;

/**
 * 
 * @ClassName: GlobalExceptionHandler
 * @Description: 统一异常处理
 * @author ldq
 * @date 2020-04-01 23:39:03
 */
@RestController
//@ControllerAdvice
//@RestControllerAdvice
public class GlobalExceptionHandler {

	private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

	/**
	 * NoHandlerFoundException 404 异常处理
	 * 请求方法不存在
	 */
	@ExceptionHandler(value = NoHandlerFoundException.class)
	@ResponseStatus(HttpStatus.NOT_FOUND)
	public <T> ResultObj<T> handlerNoHandlerFoundException(NoHandlerFoundException exception) {
		log.warn("NoHandlerFoundException 404 异常处理，code={}, message={}", 
				ResultCode.NO_HANDLER_FOUND.getCode(), ResultCode.NO_HANDLER_FOUND.getMessage());
		return ResultObj.failure(ResultCode.NO_HANDLER_FOUND);
	}
	
	/**
	 *	参数校验异常
	 * @param <T>
	 */
	@ExceptionHandler(MethodArgumentNotValidException.class)
    public <T> ResultObj<T> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
		
        // 从异常对象中拿到ObjectError对象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        log.warn("参数校验异常，code={}, message={}", 
        		ResultCode.PARAM_INVALID.getCode(), objectError.getDefaultMessage());
        // 然后提取错误提示信息进行返回
        return ResultObj.failure(ResultCode.PARAM_INVALID.getCode(), objectError.getDefaultMessage());
    }
	
	/**
	 * BindException 参数错误异常
	 */
	@ExceptionHandler(BindException.class)
	public <T> ResultObj<T> handleMethodArgumentNotValidException(BindException e) {
		log.warn("400 Bad Request BindException ", e);
		return ResultObj.failure(ResultCode.PARAM_ERROR);
	}
	
	@ExceptionHandler({ MissingServletRequestParameterException.class, HttpMessageNotReadableException.class,
        UnsatisfiedServletRequestParameterException.class, MethodArgumentTypeMismatchException.class })
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public <T> ResultObj<T> badRequestException(Exception e) {
	    log.warn("400 Bad Request methodArgumentTypeMismatchException", e);
	    return ResultObj.failure(ResultCode.PARAM_ERROR);
	}
	
	/**
	 * MissingPathVariableException 参数错误异常
	 */
	@ExceptionHandler(MissingPathVariableException.class)
	public <T> ResultObj<T> handleMethodArgumentNotValidException(MissingPathVariableException e) {
		log.warn("400 Bad Request MissingPathVariableException ", e);
		return ResultObj.failure(ResultCode.PARAM_ERROR);
	}
	
	@ExceptionHandler({ IllegalArgumentException.class })
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public <T> ResultObj<T> badRequestException(IllegalArgumentException e) {
		log.warn("400 Bad Request IllegalArgumentException ", e);
	    return ResultObj.failure(ResultCode.PARAM_ERROR);
    }
	
	
	@ExceptionHandler(Throwable.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public <T> ResultObj<T> exception(Throwable throwable) {
        log.error("系统异常", throwable);
        return ResultObj.failure(ResultCode.SYSTEM_INNER_ERROR);

    }
	
	/**
	 * 默认异常处理
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value = Exception.class)
	public Object defaultExceptionHandler(Exception e) {
		log.error("系统异常 defaultExceptionHandler ", e);
        return ResultObj.failure(ResultCode.SYSTEM_INNER_ERROR);
	}

}
